package com.yaoyong.codegenerator.utils;

import com.yaoyong.codegenerator.constant.DatabaseType;
import com.yaoyong.codegenerator.entity.Column;
import com.yaoyong.codegenerator.entity.Database;
import com.yaoyong.codegenerator.entity.Table;
import com.yaoyong.codegenerator.properties.PathProperties;
import com.yaoyong.codegenerator.properties.ProjectProperties;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据库映射文件工具类:专门用来读写db.xml
 *
 * @author 姚勇
 */
public class DbXmlUtil {

    /**
     * 返回表名称
     *
     * @param xmlPath 数据库对应xml配置所在目录
     * @return
     */
    public static List<Table> read(String xmlPath) throws DocumentException {

        List<Table> list = new ArrayList();

        SAXReader reader = new SAXReader();
        Document doc = reader.read(xmlPath);
        Element root = doc.getRootElement();

        for (Element e : root.elements()) {
            if ("table".equals(e.getName())) {
                Table table = new Table();
                table.setName(e.attributeValue("name"));
                table.setComment(e.attributeValue("comment"));
                table.setKey(e.attributeValue("key"));

                List<Column> columns = new ArrayList();
                // 字段列表
                List<Element> eList2 = e.elements();
                for (Element e2 : eList2) {
                    if (e2.getName().equals("column")) {
                        Column column = new Column();
                        column.setName(e2.attributeValue("name"));
                        column.setType(e2.attributeValue("type"));
                        column.setDbType(e2.attributeValue("db_type"));
                        column.setComment(e2.attributeValue("comment"));
                        column.setKey(Boolean.valueOf(e2.attributeValue("key")));
                        columns.add(column);
                    }
                }
                table.setColumns(columns);
                list.add(table);
            }

        }

        return list;
    }

    /**
     * 写映射文件	把数据库信息写到xml文件上
     *
     * @param database
     */
    public static void write(Database database) throws IOException {
        Document doc = DocumentHelper.createDocument();
        doc.setXMLEncoding("UTF-8");

        Element root = doc.addElement("db");
        root.addAttribute("name", database.getName());
        root.addAttribute("userName", database.getUsername());
        root.addAttribute("passWord", database.getPassword());
        root.addAttribute("url", database.getUrl());

        List<Table> tables = database.getTables();

        for (Table table : tables) {
            // 主键数量
            int keycount = 0;
            for (Column column : table.getColumns()) {
                if (column.getKey()) {
                    keycount++;
                }
            }
            // 如果是只有一个主键
            if (keycount == 1) {
                System.out.println("读取表：" + table.getName());

                Element tableElement = root.addElement("table");
                tableElement.addAttribute("name", table.getName());
                tableElement.addAttribute("comment", table.getComment() == null ? "" : table.getComment());
                tableElement.addAttribute("key", table.getKey());

                for (Column column : table.getColumns()) {
                    System.out.println("读取字段：" + column.getName());

                    Element columnElement = tableElement.addElement("column");
                    columnElement.addAttribute("name", column.getName());
                    columnElement.addAttribute("type", column.getType());
                    columnElement.addAttribute("db_type", column.getDbType());
                    columnElement.addAttribute("comment", column.getComment());
                    columnElement.addAttribute("key", String.valueOf(column.getKey()));
                    columnElement.addAttribute("decimal_digits", String.valueOf(column.getDecimal_digits()));
                    columnElement.addAttribute("column_size", String.valueOf(column.getSize()));
                    // 主键数量
                    if (column.getKey().equals("PRI")) {
                        keycount++;
                    }

                }
            }

        }

        write2Xml("temp/db.xml", doc);
    }


    /**
     * 读取缓存
     *
     * @return
     * @throws DocumentException
     */
    public static Map<String, Object> readGlobal() {
        Map<String, Object> map = new HashMap();
        try {
            SAXReader reader = new SAXReader();
            Document doc = reader.read("temp/global.xml");
            Element root = doc.getRootElement();
            for (Element e : root.elements()) {
                if ("path".equals(e.getName())) {
                    PathProperties path = new PathProperties();
                    path.setCodeGeneratorPath(e.attributeValue("codeGeneratorPath"));
                    path.setBaseTemplatePath(e.attributeValue("baseTemplatePath"));
                    map.put("path", path);
                }
                if ("project".equals(e.getName())) {
                    ProjectProperties project = new ProjectProperties();
                    project.setName(e.attributeValue("name"));
                    project.setComment(e.attributeValue("comment"));
                    project.setPackageName(e.attributeValue("packageName"));
                    project.setGroupId(e.attributeValue("groupId"));
                    project.setArtifactId(e.attributeValue("artifactId"));
                    project.setVersion(e.attributeValue("version"));
                    project.setAuthor(e.attributeValue("author"));
                    map.put("project", project);
                }
                if ("datasource".equals(e.getName())) {
                    Database database = new Database();
                    database.setName(e.attributeValue("name"));
                    database.setDatabaseType(DatabaseType.valueOf(e.attributeValue("databaseType")));
                    database.setDriverClassName(e.attributeValue("driverClassName"));
                    database.setUrl(e.attributeValue("url"));
                    database.setUsername(e.attributeValue("username"));
                    database.setPassword(e.attributeValue("password"));
                    map.put("datasource", database);
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return map;
    }


    /**
     * 缓存global配置到本地
     *
     * @param pathProperties
     * @param projectProperties
     * @param database
     * @throws IOException
     */
    public static void write(PathProperties pathProperties, ProjectProperties projectProperties, Database database) throws IOException {
        Document doc = DocumentHelper.createDocument();
        doc.setXMLEncoding("utf-8");
        Element root = doc.addElement("root");

        Element path = root.addElement("path");
        path.addAttribute("codeGeneratorPath", pathProperties.getCodeGeneratorPath());
        path.addAttribute("baseTemplatePath", pathProperties.getBaseTemplatePath());

        Element project = root.addElement("project");
        project.addAttribute("name", projectProperties.getName());
        project.addAttribute("comment", projectProperties.getComment());
        project.addAttribute("packageName", projectProperties.getPackageName());
        project.addAttribute("groupId", projectProperties.getGroupId());
        project.addAttribute("artifactId", projectProperties.getArtifactId());
        project.addAttribute("version", projectProperties.getVersion());
        project.addAttribute("author", projectProperties.getAuthor());

        Element datasource = root.addElement("datasource");
        datasource.addAttribute("name", database.getName());
        datasource.addAttribute("databaseType", database.getDatabaseType().toString());
        datasource.addAttribute("driverClassName", database.getDriverClassName());
        datasource.addAttribute("url", database.getUrl());
        datasource.addAttribute("username", database.getUsername());
        datasource.addAttribute("password", database.getPassword());

        write2Xml("temp/global.xml", doc);

    }


    /**
     * 把document对象写到指定位置生成xml文件
     *
     * @param outPath
     * @param doc
     */
    public static void write2Xml(String outPath, Document doc) throws IOException {
        File file = new File(outPath);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        // 读 进来的时候是 UTF-8,但是写出去的 时候码表变了
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        // 始终出现 乱码的原因 是 FileWriter 问题. FileWriter这个类 太弱了,以后尽量不要用它
        // XMLWriter writer = new XMLWriter(new FileWriter(file),format);
        XMLWriter writer = new XMLWriter(new FileOutputStream(file), format);
        writer.write(doc);
        writer.close();
    }
}
